#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2023/2/19 14:17
# @Author  : YueXia
# @File    : exception_handler.py
# @Description :全局异常处理
from fastapi import FastAPI, Request
from fastapi.exceptions import RequestValidationError
from fastapi.responses import ORJSONResponse
from pydantic import ValidationError
from pydantic.errors import PydanticUserError
from starlette.exceptions import HTTPException as StarletteHTTPException
from .custom_exception import BaseAppException, AuthException, PermissionException
from ..context_manager.track_utils import TrackContextUtils
from src.log import logger
from ...config import settings


async def _validation_exception_handler(e: RequestValidationError | ValidationError):
    """
    数据验证异常处理

    :param e:
    :return:
    """
    # errors = []
    errors = e.errors()
    error = errors[0]
    if error.get("type") == "json_invalid":
        message = "json解析失败"
    else:
        error_input = error.get("input")
        field = str(error.get("loc")[-1])
        error_msg = error.get("msg")
        message = f"{field} {error_msg}，输入：{error_input}"
    msg = f"请求参数非法: {message}"
    # data = {'errors': errors} if settings.ENVIRONMENT == 'dev' else None
    return ORJSONResponse(
        status_code=200,
        content={"msg": msg, "code": 422, "data": None},
        headers=get_headers(),
    )


def get_headers():
    return {"x-request-id": TrackContextUtils.get_request_id()}


def refactoring_exception(app: FastAPI):
    @app.exception_handler(PermissionException)
    def permission_exception(request: Request, exc: PermissionException):
        """
        权限异常
        :param request:
        :param exc:
        :return:
        """
        logger.warning("权限异常")
        logger.warning(f"请求地址{request.url.__str__()}")
        logger.error(exc.__str__())
        logger.error(exc.message)
        return ORJSONResponse(
            status_code=200,
            content={"msg": exc.message, "code": 403, "data": None},
            headers=get_headers(),
        )

    @app.exception_handler(AuthException)
    def token_err(request: Request, exc: AuthException):
        """
        token校验异常
        :param request:
        :param exc:
        :return:
        """
        logger.warning(f'"请求地址"{request.url.__str__()}')
        logger.error(exc.__str__())
        logger.error(exc.msg)
        return ORJSONResponse(
            status_code=200,
            content={"msg": exc.msg, "code": 401, "data": None},
            headers=get_headers(),
        )

    @app.exception_handler(BaseAppException)
    def app_err(request: Request, exc: BaseAppException):
        """
        自定义异常,比如。权限异常，用户不存在等。。。
        :param request:
        :param exc:
        :return:
        """
        logger.warning(f'"请求地址"{request.url.__str__()}')
        logger.warning("捕捉到重写AppException异常异常：custom_exception_handler")
        logger.error(exc.__str__())
        logger.error(exc.msg)
        return ORJSONResponse(
            status_code=200,
            content={"msg": exc.msg, "code": exc.code, "data": None},
            headers=get_headers(),
        )

    @app.exception_handler(ValidationError)
    async def validation_error(request: Request, exc: ValidationError):
        """
        处理参数异常
        :param request:
        :param exc:
        :return:
        """
        logger.warning("请求地址", request.url.__str__())
        logger.error(exc.__str__())
        logger.error(exc.__str__())
        return await _validation_exception_handler(exc)

    @app.exception_handler(RequestValidationError)
    async def request_validation_error(request: Request, exc: RequestValidationError):
        """
        全局请求数据验证异常处理,处理请求参数验证的异常
        :param request:
        :param exc:
        :return:
        """
        logger.warning("请求地址", request.url.__str__())
        logger.error(exc.errors())
        return await _validation_exception_handler(exc)

    @app.exception_handler(StarletteHTTPException)
    async def http_exception_handler(request: Request, exc: StarletteHTTPException):
        """处理客户端请求异常
        code: 312 404
        """
        logger.warning("请求地址", request.url.__str__())
        # 获取状态码
        _status = exc.status_code
        msg = exc.detail
        if _status == 404:
            msg = "接口不存在"
        else:
            logger.error(exc.detail)
        return ORJSONResponse(
            status_code=200,
            content={"msg": msg, "code": exc.status_code, "data": None},
            headers=get_headers(),
        )

    @app.exception_handler(PydanticUserError)
    async def pydantic_user_error_handler(request: Request, exc: PydanticUserError):
        """
        Pydantic 未正确使用导致的异常处理

        :param request:
        :param exc:
        :return:
        """
        return ORJSONResponse(
            status_code=200,
            content={"msg": "服务器异常", "code": 500, "data": None},
            headers=get_headers(),
        )

    @app.exception_handler(ValueError)
    async def value_exception_handler(request: Request, exc: ValueError):
        """
        捕获值异常
        """
        if settings.system.DEBUG:
            logger.warning("请求地址{}", request.url.__str__())
            logger.warning("捕捉到值异常：value_exception_handler")
            logger.warning(exc.__str__())
        # 打印栈信息，方便追踪排查异常
        logger.exception(exc)
        return ORJSONResponse(
            status_code=200, content={"msg": exc.__str__(), "code": 400, "data": None}
        )

    @app.exception_handler(AssertionError)
    async def assertion_error_handler(request: Request, exc: AssertionError):
        """
        断言错误处理

        :param request:
        :param exc:
        :return:
        """
        logger.error("=======断言错误处理=========")
        logger.exception(exc)
        return ORJSONResponse(
            status_code=200,
            content={"msg": "服务器异常", "code": 500, "data": None},
            headers=get_headers(),
        )

    @app.exception_handler(Exception)
    async def all_exception_handler(request: Request, exc: Exception):
        """
        全局异常处理
        :param request:
        :param exc:
        :return:
        """
        logger.warning("请求地址", request.url.__str__())
        logger.exception(exc)
        return ORJSONResponse(
            status_code=200,
            content={"msg": "服务器异常", "code": 500, "data": None},
            headers=get_headers(),
        )
